﻿using System.Collections;
using System.Collections.Generic;
using System.Threading;
namespace YanZhiwei.DotNet2.Utilities.Base
{
    /// <summary>
    /// 基于IEnumerator的线程安全的实现
    /// 参考: http://www.codeproject.com/KB/cs/safe_enumerable.aspx
    ///       http://theburningmonk.com/2010/03/thread-safe-enumeration-in-csharp/
    /// </summary>
    public class ThreadSafeEnumerator<T> : IEnumerator<T>
    {
        #region 构造函数以及变量
        // this is the (thread-unsafe)
        // enumerator of the underlying collection
        private readonly IEnumerator<T> _inner;
        // this is the object we shall lock on.
        private readonly object _lock;
        /// <summary>
        /// ThreadSafeEnumerator构造函数
        /// </summary>
        /// <param name="inner">IEnumerator</param>
        /// <param name="lock">object</param>
        public ThreadSafeEnumerator(IEnumerator<T> inner, object @lock)
        {
            _inner = inner;
            _lock = @lock;
            // entering lock in constructor
            Monitor.Enter(_lock);
        }
        #endregion
        #region 返回当前类型
        /// <summary>
        /// 返回当前类型
        /// </summary>
        public T Current
        {
            get { return _inner.Current; }
        }
        object IEnumerator.Current
        {
            get { return Current; }
        }
        #endregion
        #region Dispose
        /// <summary>
        /// Dispose
        /// </summary>
        public void Dispose()
        {
            // .. and exiting lock on Dispose()
            // This will be called when foreach loop finishes
            Monitor.Exit(_lock);
        }
        #endregion
        #region MoveNext
        /// <summary>
        /// MoveNext
        /// </summary>
        /// <returns>bool</returns>
        public bool MoveNext()
        {
            return _inner.MoveNext();
        }
        #endregion 
        #region Reset
        /// <summary>
        /// Reset
        /// </summary>
        public void Reset()
        {
            _inner.Reset();
        }
        #endregion 
    }
}